from fastapi import FastAPI, Request, Depends
from fastapi.middleware import Middleware
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from redis import Redis
from sqlalchemy import Engine, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from fastapi.staticfiles import StaticFiles
from .settings import meta_settings
from app.settings import meta_settings
from app.common.log import init_logger
from app.common import cache

from app.config import ConfigObj, init_conf

#conf: ConfigObj = ConfigObj()
conf: ConfigObj = init_conf(ConfigObj)

ctx_conf = {}

engine = create_engine(
    conf.SQLALCHEMY_DATABASE_URL,
    pool_recycle=600
)
    
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

########################### lifespan ###########################
@asynccontextmanager
async def lifespan(app: FastAPI):
    # Setup
    cache.r = cache.init_redis_pool(conf)
    app.r: Redis = cache.r
    yield
    # Clean up
    cache.r.close()


########################### 创建APP ###########################

def create_app() -> FastAPI:
    print('>> create_app')
    #app = FastAPI(**meta_settings,
    #              )
    ######################### Middlewares ##########################
    from app.extensions import middleware as midw
    middlewares = [
        #Middleware(midw.CustomHeaderMiddleware, header_value='Customized'),
        Middleware(midw.SecCheckMiddleware, 
                #allowed_hosts=["localhost"],
                allowed_hosts=conf.ALLOWED_HOSTS,
                allowed_uris=conf.ALLOWED_URIS,
        )
    ]
    app = FastAPI(**meta_settings, 
        #dependencies=[Depends(deps.verify_signature_header)],
        #dependencies=[Depends(SignatureChecker), Depends(get_query_token)],
        #middleware=middlewares,
        lifespan=lifespan
    )
    ctx_conf['app'] = app

    # 添加中间件
    app.add_middleware(
        CORSMiddleware,
        #allow_origins=[],
        allow_origins=conf.ORIGINS,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    #from app.common import init_logger
    # init
    init_logger(conf)
    ########################## Exeptions ###########################
    from app.common import exceptions
    from fastapi.exceptions import RequestValidationError
    from starlette.exceptions import HTTPException as StarletteHTTPException

    '''
    @app.exception_handler(HTTPException)
    async def http_exception_handler(request, exc):
        task = BackgroundTasks(notice_util.test_notice('test msg...'), message=exc.detail)
        return PlainTextResponse(str(exc.detail), status_code=exc.status_code, background=task)
    '''
    @app.exception_handler(exceptions.GenericException)
    async def generic_exception_handler(request: Request, exc: exceptions.GenericException):
        return await exceptions.generic_exception_handler(request, exc)

    @app.exception_handler(StarletteHTTPException)
    async def http_exception_handler(request, exc):
        print('>> http_exception_handler')
        #response = PlainTextResponse(str(exc.detail), status_code=exc.status_code)
        #response = PlainTextResponse(str(exc.detail), status_code=exc.status_code)
        #response.background = BackgroundTask(notice_util.test_notice('silly error.'), message=exc.detail)
        return await exceptions.custom_http_exception_handler(request, exc)  

    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request, exc):
        print(f"request_validation_exception_handler: {exc}")
        return await exceptions.request_validation_exception_handler(request, exc)
        #return await request_validation_exception_handler(request, exc)
    '''
    @app.exception_handler(HTTPException)
    async def forbidden_exception_handler(request, exc):
        print(f"OMG! The client sent invalid data!: {exc}")
        return await exceptions.forbidden_exception_handler(request, exc)
    '''
    '''
    @app.exception_handler(exceptions.UnicornException)
    async def unicorn_exception_handler(request: Request, exc: exceptions.UnicornException):
        return JSONResponse(
            status_code=418,
            content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
        )
    '''

    # register routers
    from app.routers import demo_router, v1_router, debug_router
    app.include_router(demo_router)
    app.include_router(debug_router)
    app.include_router(v1_router)

    # static
    app.mount("/static", StaticFiles(directory="static"), name="static")

    @app.get("/prjName")
    async def root():
        return {"app": "openapi"}

    return app
